﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;

namespace XCommunity.Metas
{


  public abstract class MetaContainer
  {

    private Hashtable _dictionary = new Hashtable();

    private IDictionary Items
    {
      get { return _dictionary; }
    }


    /// <summary>
    /// 获取指定类型的元数据
    /// </summary>
    /// <typeparam name="MetaType">元数据类型</typeparam>
    /// <returns>元数据</returns>
    public MetaType GetMeta<MetaType>()
    {

      MetaType metaData;
      if ( !TryGetMeta<MetaType>( out metaData ) )
        throw new InvalidOperationException();//UNDONE 异常详细信息

      return metaData;
    }


    /// <summary>
    /// 尝试获取指定类型的元数据
    /// </summary>
    /// <typeparam name="MetaType">元数据类型</typeparam>
    /// <param name="metaData">元数据</param>
    /// <returns>是否成功</returns>
    public bool TryGetMeta<MetaType>( out MetaType metaData )
    {
      Type metaType = typeof( MetaType );

      if ( !metaType.IsSealed )
        throw new InvalidOperationException( "检索的元数据必须是封闭类型" );

      lock ( Items.SyncRoot )
      {
        if ( Items.Contains( metaType ) )
        {
          metaData = (MetaType) Items[metaType];
          return true;
        }
        else
        {
          if ( !TryLoadMeta<MetaType>( out metaData ) )
          {
            Items.Add( metaType, metaData );
            return true;
          }
          else
            return false;
        }
      }
    }

    /// <summary>
    /// 尝试加载指定类型的元数据
    /// </summary>
    /// <typeparam name="MetaType">元数据类型</typeparam>
    /// <returns></returns>
    private bool TryLoadMeta<MetaType>( out MetaType metaData )
    {
      IMetaLoader<MetaType> loader = GetLoader<MetaType>();
      if ( loader == null )
      {
        metaData = default( MetaType );
        return false;
      }

      metaData = loader.LoadMeta( this );
      return true;
    }


    /// <summary>
    /// 获取指定类型元数据的加载器
    /// </summary>
    /// <typeparam name="T">元数据类型</typeparam>
    /// <returns></returns>
    public IMetaLoader<T> GetLoader<T>()
    {
      Type metaType = typeof( T );

      MetaAttribute metaAttribute = metaType.GetCustomAttributes( typeof( MetaAttribute ), false ).FirstOrDefault() as MetaAttribute;

      if ( metaAttribute == null )
        return null;

      if ( !metaAttribute.ContainerType.IsAssignableFrom( this.GetType() ) )
        throw new InvalidOperationException();

      Type persisterInterfaceType = typeof( IMetaLoader<T> );

      if ( persisterInterfaceType.IsAssignableFrom( metaAttribute.PersisterType ) )
        throw new InvalidOperationException();

      return Activator.CreateInstance( metaAttribute.PersisterType ) as IMetaPersister<T>;
    }
  }
}
